#pragma once

#include "Connection.hpp"

class handerConnection
{
public:
    handerConnection(func_t func)
        : _func(func)
    {
    }
    void handlerRecver(connection *conn)
    {
        errno = 0;
        while (true)
        {
            char buffer[1024] = {0};
            int n = ::recv(conn->getFd(), buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                conn->appendInbuffer(buffer);
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    // 出现异常，交给异常函数处理（不止是读的异常，也有可能是其他异常）
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        _func(conn); // 对读取的数据作分析
    }

    // 发送时，关心的是发送缓冲区的空间
    // 因此，第一次发送时，缓冲区是一定有空间的
    // 即，写事件一定是就绪的，并且大部分情况下，写事件都是就绪的
    // 只有当发送缓冲区被写满时，写事件才不会就绪
    // 因此，不建议直接设置epoll对写事件的关心，应该在发送缓冲区占满的情况下，才设置对该fd写事件的关心
    // 这样，当发送缓冲区重新有空间时，reactor会自动调用连接的写函数，发送完剩下的数据
    void handlerSender(connection *conn)
    {
        errno = 0;
        while (true)
        {
            int fd = conn->getFd();
            int n = ::send(fd, conn->getOutbuffer().c_str(), conn->getOutbuffer().size(), 0); // 直接将所有的数据都发送
            if (n > 0)
            {
                conn->removeOutbuffer(n);   // 将发送的数据移除
                if (conn->outbufferEmpty()) // 所有数据都已经发送完毕
                    break;
            }
            else if (n == 0)
            {
                break; // 所有数据都已经发送完毕
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN) // 发送缓冲区满了
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    // 发生了错误
                    conn->_excepter(conn);
                    return;
                }
            }
            if (conn->outbufferEmpty())
            {
                // 如果数据被发送完了，就要关闭对写事件的关心
                conn->_r->enableReadWirte(conn->getFd(), true, false);
            }
            else
            {
                // 设置对conn写事件的关心
                conn->_r->enableReadWirte(conn->getFd(), true, true);
            }
        }
    }

    void handlerExcepter(connection *conn)
    {
        LOG(INFO, "client exited, fd: %d", conn->getFd());

        //关闭连接
        conn->_r->delConnection(conn->getFd());
    }

private:
    func_t _func;
};